/*
 * Created on Sep 12, 2004
 *
 */
package com.tgjorgoski.spellcheck;

import java.io.*;
import java.net.*;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.zip.*;

import com.swabunga.spell.engine.*;
import com.swabunga.spell.event.SpellChecker;


/**
 * Convert this to singletone ?
 * FIXME: For some clients user might not be interested in userdictionary vs. dictionary.
 * Just checking words and add. Rework so it makes more sense for such clients.
 * <br>
 * From other side there should be methods for: changing user dictionary, changing main dictionary...
 * Both should throw events. Also...  
 *  
 * @author Tanasije Gjorgoski <tgjorgoski@novizio.com>
 */
public class SpellcheckDictionaries {
	private static SpellDictionary userDictionary;
	private static SpellDictionary dictionary;
	private static boolean installingOfDictionaryFailed=false;
	private static String DICTIONARY_PATH = "com/tgjorgoski/spellcheck/";
	private static String DICTIONARY_NAME = "english.0.zip";
	private static String USER_DICTIONARY_NAME = "userDictionary.dic";
	private static Vector listeners = new Vector();
	private static SpellChecker spellCheck;
	private static List ignoredWords = new Vector();

	private static SpellDictionary getDictionary() {
		if (isDictionaryAvailable())
			return dictionary;
		else
			return null;
	}
	public static boolean isDictionaryAvailable() {
		if (dictionary!=null) return true;
		if (installingOfDictionaryFailed) return false;
		//nobody tried to install dictionary, try to install the default one
		String dictPath = DICTIONARY_PATH + DICTIONARY_NAME;
		URL dictURL = SpellcheckDictionaries.class.getClassLoader().getResource(dictPath);
		if (dictURL==null) {
			installingOfDictionaryFailed=true;
			return false;
		}
		boolean success = installDictionary(dictURL); 
		if (!success) installingOfDictionaryFailed=true;
		return success;
	}
	public static boolean installDictionary(URL dictURL) {
		ZipInputStream zip;
		try {
			zip = new ZipInputStream(dictURL.openStream());
			zip.getNextEntry();
			SpellDictionaryHashMap dd = new SpellDictionaryHashMap(new BufferedReader(new InputStreamReader(zip)));
				while (zip.getNextEntry()!=null) {
					dd.addDictionary(new BufferedReader(new InputStreamReader(zip)));
				}
				dictionary = dd; 
			} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	public static SpellDictionary getUserDictionary() {
		return userDictionary;
	}
	public static void addWord(String word) {
	    if (userDictionary!=null) {
	        userDictionary.addWord(word);
	        fireUserDictionaryModified();
	    }
	}
	public static boolean isCorrect(String word) {
	    if (isDictionaryAvailable() && dictionary.isCorrect(word)) return true;
	    if (userDictionary!=null && userDictionary.isCorrect(word)) return true;
	    if (ignoredWords.contains(word.toLowerCase())) return true;
	    return false;
	}
	
	private static SpellChecker getSpellChecker() {
	    if (spellCheck==null) {
		    if (!isDictionaryAvailable()) return null;
		    spellCheck=new SpellChecker(dictionary);
		    if (userDictionary!=null) {
		        spellCheck.setUserDictionary(userDictionary);
		    }
	    }
	    return spellCheck;
	}
	public static SpellChecker constructSpellChecker() {
	    SpellChecker sc = null;
	    if (isDictionaryAvailable()) {
	        sc = new SpellChecker(dictionary);
		    if (userDictionary!=null) {
		        sc.setUserDictionary(userDictionary);
		    }
	    }
	    return sc;
	}
	
	public static List getSuggestions(String word, int level) {
	    SpellChecker sc = getSpellChecker();
	    if (sc==null) return new Vector();
	    return sc.getSuggestions(word, level); 
	}
	
	public static void addDictionaryChangesListener(DictionaryChangeListener dcl) {
	    listeners.add(dcl);
	}
	public static void removeDictionaryChangesListener(DictionaryChangeListener dcl) {
	    listeners.remove(dcl);
	}
	public static void fireUserDictionaryModified() {
	    for (Iterator iter = listeners.iterator(); iter.hasNext();) {
            DictionaryChangeListener listener = (DictionaryChangeListener) iter.next();
            listener.userDictionaryModified();
        }
	}
	//set the user dictionary
	static {
		String userHome = System.getProperty("user.home");
		if (userHome!=null) {
			String userDictName = userHome + "/" + USER_DICTIONARY_NAME;
			File userDictFile = new File(userDictName);
			if (!userDictFile.exists()) {
				try {
					userDictFile.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (userDictFile.exists()) {
				try {
					userDictionary= new SpellDictionaryHashMap(userDictFile);
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	public static void ignoreWord(String word) {
	    if (!ignoredWords.contains(word.toLowerCase())) {
		    ignoredWords.add(word.toLowerCase());
		    fireUserDictionaryModified();
	    }
	}
	public static List getIgnoredWords() {
	    return ignoredWords;
	}
}
